<template>
    <center>
        <el-container>
            <el-header>
                <h1>银行家算法</h1>
            </el-header>
            <el-main>
                <!-- input页 -->
                <div id="input" v-if="process == 1">
                    <el-row>
                        <el-col :span="8">请输入进程数：</el-col>
                        <el-col :span="16"><el-input size="mini" v-model="num_process" placeholder="请输入内容" id="t_process" name="t_process"></el-input></el-col>
                    </el-row>
                    <br />
                    <el-row>
                        <el-col :span="8">请输入资源数：</el-col>
                        <el-col :span="16"><el-input size="mini" v-model="num_resource" id="t_resource" name="t_resource" placeholder="请输入内容"></el-input></el-col>
                    </el-row>
                    <br />
                    <el-button type="primary" value="确定" name="b_ok" @click="onClickOK">确定</el-button>
                    <br />
                </div>
                <!-- 输入资源 -->
                <div v-if="process == 2">
                    <h2>请输入对应的资源数目</h2>
                    <el-row v-for="value in num_resource*1" :key="value">
                        <el-col :span="8">第{{value}}个资源总数：</el-col>
                        <el-col :span="16"><input class="input_sou_style" placeholder="请输入内容" type="text" :id="'input_sou_'+value" @blur="inputF(value-1,$event)"></el-col>
                    </el-row>
                    <br />
                    <el-button type="primary" value="确定" name="b_ok" @click="confirmSource">确定</el-button>
                </div>
                <!-- 生成表格 -->
                <div v-if="process == 3">
                    <h2>系统资源的总数依次是：<span v-for="(item,index) in availableTitle" :key="index">{{item+' '}}</span></h2>
                    <hr>
                    <h3>请输入各个进程的最大需求数(Max)和已分配数(Allocation)</h3>
                    <table border=1 cellspacing=1 width=80% style='text-align:center;border-collapse:collapse;border:1px solid #ccc;'>
                        <tr>
                            <td>资源</td>
                            <td :colspan='Number(num_resource)'>Max</td>
                            <td :colspan='Number(num_resource)'>Allocation</td>
                            <td :colspan='Number(num_resource)'>Need</td>
                            <td :colspan='Number(num_resource)'>Available</td>
                        </tr>
                        <tr v-for="(items,indexs) in helpObjArr" :key="indexs">
                            <td>{{items.name}}</td>
                            <td v-for="(item,index) in items.max" :key="'max'+index">
                                <input class= 'numtext' type="text" :value="item" @blur="tdInput('max',indexs,index,$event)">
                            </td>
                            <td v-for="(item,index) in items.allocation" :key="'allocation'+index">
                                <input class= 'numtext' type="text" :value="item" @blur="tdInput('allocation',indexs,index,$event)">
                            </td>
                            <td v-for="(item,index) in items.need" :key="'need'+index">
                                <input class= 'numtext' type="text" readonly :value="item">
                            </td>
                            <td v-for="(item,index) in items.available" :key="'available'+index">
                                <input class= 'numtext' type="text" readonly :value="item">
                            </td>
                        </tr>
                    </table>
                    <br /><br />
                    <!-- 有时间优化一下，有未填的按钮不允许按 -->
                    <el-button type="success" name="b_ok2"  @click="onClickOK2">提交检查</el-button>
                    <el-button type="warning" name="b_ok3"  @click="Banker">请求资源</el-button>
                    <hr>
                    <h3>{{safeStr}}</h3>
                    <table v-if="showSafeTable" border=1 cellspacing=1 width=80% style='text-align:center;border-collapse:collapse;border-width:thin;border-style:solid;margin:0;'>
                        <tr>
                            <td>资源</td>
                            <td :colspan='Number(num_resource)'>Work</td>
                            <td :colspan='Number(num_resource)'>Need</td>
                            <td :colspan='Number(num_resource)'>Allocation</td>
                            <td :colspan='Number(num_resource)'>Work+Allocation</td>
                            <td>Finish</td>
                        </tr>
                        <tr>
                            <td>进程</td>
                            <td v-for="value in Number(num_resource)" :key="'Work'+value">{{String.fromCharCode((64+value))}}</td>
                            <td v-for="value in Number(num_resource)" :key="'Need'+value">{{String.fromCharCode((64+value))}}</td>
                            <td v-for="value in Number(num_resource)" :key="'Allocation'+value">{{String.fromCharCode((64+value))}}</td>
                            <td v-for="value in Number(num_resource)" :key="'Work+Allocation'+value">{{String.fromCharCode((64+value))}}</td>
                            <td></td>
                        </tr>
                        <tr v-for="(items,indexs) in helpObjArr2" :key="indexs">
                            <td>{{items.name}}</td>
                            <td v-for="(item,index) in items.work" :key="'work'+index">
                                <input class= 'numtext' type="text" readonly :value="item">
                            </td>
                            <td v-for="(item,index) in items.need" :key="'need'+index">
                                <input class= 'numtext' type="text" readonly :value="item">
                            </td>
                            <td v-for="(item,index) in items.allocation" :key="'allocation'+index">
                                <input class= 'numtext' type="text" readonly :value="item">
                            </td>
                            <td v-for="(item,index) in items.workAllocation" :key="'workAllocation'+index">
                                <input class= 'numtext' type="text" readonly :value="item">
                            </td>
                            <td>
                                <input class= 'numtext' type="text" readonly :value="items.finish">
                            </td>
                        </tr>
                    </table>
                </div>
            </el-main>
        </el-container>
    </center>
</template>

<script>
export default {
    data() {
        return {
            num_process: '', //记录进程数
            num_resource: '', //记录资源数
            process: 1, // 当前进度
            availableTitle: [], // 可利用资源数目
            available: [], // 可利用资源数目
            // isb_ok2: false, // 按钮是否可用
            helpObjArr: [], // 辅助对象数组[{name:'',max:['','',''],available:['','',''],allocation:['','',''],need:['','','']}]
            fg: false, //更新Available标志
            work: [], //资源可用数
            work2: [], //用于记录每次进程调用的Work数
            finish: [], //是否已完成
            o: 0,
            safe: [], //安全序列
            safeStr: '', // 展示安全序列，不安全则提出警告
            showTable2: false, // 
            request: [],//请求资源数
            helpObjArr2: [],// 辅助对象数组[{name:'',work:['','',''],need:['','',''],allocation:['','',''],work+allocation:['','',''],finish:false}] 
            showSafeTable: false, // 是否展示安全表格，可得到安全序列则展示
        }
    },
    methods: {
        // 点击第一个按钮
        onClickOK() {
            if(this.num_process && this.num_resource){
                this.$confirm(`${this.num_process}个进程${this.num_resource}个资源`, {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    this.process = 2; // 隐藏初试页面，进入第二个步骤
                }).catch(() => {     
                });
            }else{
                this.$message({
                    message: '请输入数字',
                    type: 'warning'
                });
            }
        },
        // 输入对应的资源
        inputF(index,e) {
            this.availableTitle[index] = e.target.value
            this.available[index] = e.target.value
        },
        // 在这里生成对应的表格
        confirmSource() {
            this.process = 3
            this.createTable1()
        },
        // 生成表格1
        createTable1() {
            console.log('createTable1')
            for (let i=0;i<= this.num_process;i++) {
                let arr = []
                let maxArr = []
                let availableArr = []
                let allocationArr = []
                let needArr = []
                for (let ii=0;ii<this.num_resource;ii++) {
                    arr.push(String.fromCharCode(65+ii))
                    maxArr.push('')
                    availableArr.push('')
                    allocationArr.push('')
                    needArr.push('')
                }
                this.helpObjArr.push({
                    name: i==0?'进程':'P'+(i-1),
                    max: i==0?arr:maxArr,
                    available: i==0?arr:availableArr,
                    allocation: i==0?arr:allocationArr,
                    need: i==0?arr:needArr,
                })
            }
        },
        // 表格中输入的内容
        tdInput(type,indexs,index, e) {
            this.helpObjArr[indexs][type][index] = Number(e.target.value) // 将输入的数据存入表格中,需注意存入的是数字类型
        },
        // 提交检查
        onClickOK2() {
            console.log('提交检查',this.helpObjArr)
            this.ChickSequence();
            this.PrintSequence("outputlist");
        },
        // 得到并填充Need
        getNeed() {
            for (let item in this.helpObjArr) {
                if(item>0) {
                    for(let i in this.helpObjArr[item].max){
                        this.helpObjArr[item].need[i] = this.helpObjArr[item].max[i] - this.helpObjArr[item].allocation[i]
                    }
                }
            }
            // 触发刷新
            this.$forceUpdate()
        },
        //获得安全序列
        ChickSequence(){
            console.log('获得安全序列')
            this.getNeed()
            this.GetAvailable(this.fg)
            this.GetWork()
            //初始化work2
            for(let i=0;i<(this.num_process+1);i++){
                this.work2[i] = new Array();
            }
            for(let i=0;i<this.num_resource;i++){
                this.work2[0][i] = this.work[i];
            }
            //初始化finish
            for(let i=0;i<this.num_process;i++){
                this.finish[i] = false;
            }
            this.o = 0;
            //算法核心！！！
            while(this.o < this.num_process){
                this.flag = false;
                for(let i = 0; i < this.num_process; i ++){
                    if(this.finish[i])
                    continue;
                    let j;
                    for( j = 0; j < this.num_resource; j ++){
                        if(this.helpObjArr[i+1].need[j] > this.work[j])
                        break;
                    }
                    if(j == this.num_resource){
                        this.flag = true;
                        this.safe[this.o] = i;
                        this.o++;
                        this.finish[i] = true;
                        for(let k = 0; k < this.num_resource; k ++){
                            this.work[k] += this.helpObjArr[i+1].allocation[k];
                            this.work2[this.o][k] = this.work[k];
                        }             
                    }
                }
                if(!this.flag)
                break;
            }
        },
        //输出安全序列
        PrintSequence(id){
            console.log('输出安全序列',id)
            if(this.o == this.num_process){
                console.log('safe',this.safe,this.o)
                this.safeStr = '该资源是安全的;安全序列为:'
                for (let i=0;i<this.o;i++) {
                    this.safeStr += 'P'+this.safe[i]
                    if(i<this.o-1){
                        this.safeStr += '->'
                    }
                }
                this.showSafeTable = true // 展示安全表格
            }else {
                this.safeStr = '对不起，该资源状态不安全！'
                return;
            }
            this.chickSafeTable();
        },
        //创建安全表格
        chickSafeTable(){
            console.log('创建安全表格')
            for(let i=0;i<this.num_process;i++){
                this.helpObjArr2[i] = {name:'P'+this.safe[i],work:[],need:[],allocation:[],workAllocation:[],finish:false}
                // 填充安全表格
                for(let j=0;j<this.num_resource;j++){
                    this.helpObjArr2[i].work.push(this.work2[i][j])
                    this.helpObjArr2[i].need.push(this.helpObjArr[parseInt(this.safe[i])+1].need[j]) // parseInt(this.safe[i])+1这里加一的原因，表格一中ABC那一行我加入了数组中，表格二把ABC单独分开了，没放进数组
                    this.helpObjArr2[i].allocation.push(this.helpObjArr[parseInt(this.safe[i])+1].allocation[j])
                    this.helpObjArr2[i].workAllocation.push(this.work2[i][j]+this.helpObjArr[parseInt(this.safe[i])+1].allocation[j])
                    this.helpObjArr2[i].finish=this.finish[this.safe[i]]
                }  
            }
            // 触发刷新
            this.$forceUpdate()
        },
        //得到并填充Available
        GetAvailable(fg){
            //计算Available
            if(!fg){
                for(let i=0;i<this.num_resource;i++){
                    for(let j=0;j<this.num_process;j++){
                        this.available[i] -= this.helpObjArr[j+1].allocation[i];
                        if(this.available[i]<0){
                            this.$message({
                                message: '请求失败！无可利用资源',
                                type: 'warning'
                            });
                            return false;
                        }
                    }
                }
                this.helpObjArr[1].available = this.available
                // 触发刷新
                this.$forceUpdate()
            }
            return true;
        },
        //得到Work
        GetWork(){
            for(let j=0;j<this.num_resource;j++){
                this.work[j]=this.available[j];
            }
            console.log('得到Work',this.work)
        },
        //新请求资源
        Banker(){
            console.log('提交检查')
            this.fg = true;
            var v1 = parseInt(window.prompt("请输入第几个进程请求资源"));
            if(isNaN(v1)){
                this.$message({
                    message: '请输入数字！',
                    type: 'warning'
                });
                return;
            }
            if(v1>this.num_process){
                this.$message({
                    message: '没有该进程！',
                    type: 'warning'
                });
                return;
            }
            for(let i=0;i<this.num_process;i++){
                this.request[i] = new Array();
            }
            for(let j=0;j<this.num_resource;j++){
                this.request[v1-1][j] = window.prompt("进程P"+(v1-1)+"请求资源"+String.fromCharCode((65+j))+"数量：");
                console.log(this.request[v1-1][j],typeof(this.request[v1-1][j]))
                if(isNaN(this.request[v1-1][j]) || this.request[v1-1][j]===''){
                    this.$message({
                        message: '请输入数字！',
                        type: 'warning'
                    });
                    return;
                }
            }
            for(let j=0;j<this.num_resource;j++){
                if(this.request[v1-1][j]>this.helpObjArr[v1].need[j]){
                    this.$message({
                        message: '请求资源数大于所需最大值，失败！',
                        type: 'warning'
                    });
                    return;
                }else if(this.request[v1-1][j]>this.available[j]){
                    this.$message({
                        message: '请求资源数大于可利用资源量，请等待！',
                        type: 'warning'
                    });
                    return;
                }else{
                    this.available[j] -= this.request[v1-1][j];
                    var v2 = parseInt(this.helpObjArr[v1].allocation[j]);
                    var v3 = parseInt(this.request[v1-1][j]);
                    this.helpObjArr[v1].allocation[j] = v2+v3;
                    this.helpObjArr[v1].need[j] -= this.request[v1-1][j];
                }
            }
            this.ChickSequence();
            this.PrintSequence("output2");
        },
    }
}
</script>
